package com.drakulo.games.ais.ui.component.button;

import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;

import com.drakulo.games.ais.core.audio.SoundHelper;
import com.drakulo.games.ais.ui.component.ActionHandler;
import com.drakulo.games.ais.ui.component.UIComponent;

/**
 * A UI button
 * 
 * @author Drakulo
 * 
 */
public abstract class Button extends UIComponent {
	protected static final int NORMAL = 0;
	protected static final int HOVERED = 1;
	protected static final int PRESSED = 2;
	protected static final int DISABLED = 3;

	public static final int DEFAULT_WIDTH = 100;
	public static final int DEFAULT_HEIGHT = 20;

	/** The button state (for rendering effects) */
	protected int state;
	/** The click action defined */
	protected ActionHandler actionHandler;
	/** The hover action */
	protected ActionHandler hoverHandler;
	/** Disabled flag */
	protected boolean disabled;

	/**
	 * Basic constructor with default settings
	 */
	public Button() {
		this(0, 0);
	}

	/**
	 * Simple constructor
	 * 
	 * @param x
	 *            X coordinate
	 * @param y
	 *            Y coordinate
	 */
	public Button(int x, int y) {
		this(x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT);
	}

	/**
	 * Full constructor
	 * 
	 * @param x
	 *            X coordinate
	 * @param y
	 *            Y coordinate
	 * @param width
	 *            the button width
	 * @param height
	 *            the button height
	 */
	public Button(int x, int y, int width, int height) {
		this.width = width;
		this.height = height;
		setPosition(x, y);
		this.disabled = false;
		this.show();
	}

	@Override
	public void render(Graphics g) throws SlickException {
		if (!this.isShown()) {
			return;
		}
		// According to the current button state, the rendering may change
		switch (this.state) {
		case HOVERED:
			g.setColor(Color.gray);
			g.fill(this.zone);
			g.setColor(Color.black);
			g.draw(this.zone);
			break;
		case PRESSED:
			g.setColor(Color.darkGray);
			g.fill(this.zone);
			g.setColor(Color.lightGray);
			g.draw(this.zone);
			break;
		case DISABLED:
			g.setColor(Color.darkGray);
			g.fill(this.zone);
			g.setColor(Color.gray);
			g.draw(this.zone);
			break;
		case NORMAL:
		default:
			g.setColor(Color.lightGray);
			g.fill(this.zone);
			g.setColor(Color.darkGray);
			g.draw(this.zone);
			break;
		}
	}

	@Override
	public void update(Input input) throws SlickException {
		if (!this.isShown()) {
			return;
		}
		if (this.disabled) {
			// The button is disabled. No input is handled
			this.state = DISABLED;
			this.updateHovered(-10, -10); // Force hover to be disabled
			return;
		}
		int mouseX = input.getMouseX();
		int mouseY = input.getMouseY();
		this.updateHovered(mouseX, mouseY);
		// According to the mouse position, the button state is changed
		if (this.isHovered()) {
			// The mouse is on the button
			if (input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON)) {
				// The player is clicking on it
				this.state = PRESSED;
			} else {
				// If the previous state was PRESSED, the player clicked on the
				// button. The action must be done then
				if (this.state == PRESSED) {
					if (this.actionHandler != null) {
						// Play the click sound
						SoundHelper.playSound(SoundHelper.BUTTON_CLICK);
						this.actionHandler.run();
					}
				}
				// The player moved the cursor on the button
				this.state = HOVERED;
				if (this.hoverHandler != null) {
					// If there is a hover handler, we run it
					this.hoverHandler.run();
				}
			}
		}else{
			this.state = NORMAL;
		}
	}

	public void setActionHandler(ActionHandler handler) {
		this.actionHandler = handler;
	}

	public void setHoverHandler(ActionHandler handler) {
		this.hoverHandler = handler;
	}

	public void setPosition(int x, int y) {
		setOX(x);
		setOY(y);
	}

	public void setSize(int width, int height) {
		setWidth(width);
		setHeight(height);
	}

	public void disable() {
		this.disabled = true;
	}

	public void enable() {
		this.disabled = false;
	}
}
